package com.example.system.Service.exam.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.example.common.core.constants.CacheConstants;
import com.example.common.core.domain.R;
import com.example.common.core.domain.ResultCode;
import com.example.common.core.domain.TableDataInfo;
import com.example.security.exception.ServiceException;
import com.example.service.RedisService;
import com.example.system.Service.exam.IExamService;
import com.example.system.domain.exam.Exam;
import com.example.system.domain.exam.ExamQuestion;
import com.example.system.domain.exam.dto.ExamAddDTO;
import com.example.system.domain.exam.dto.ExamQueryDTO;
import com.example.system.domain.exam.dto.ExamQuestionAddDTO;
import com.example.system.domain.exam.dto.ExamQuestionDeleteDTO;
import com.example.system.domain.exam.vo.ExamQuestionVO;
import com.example.system.domain.exam.vo.ExamVo;
import com.example.system.domain.question.Question;
import com.example.system.mapper.ExamMapper;
import com.example.system.mapper.ExamQuestionMapper;
import com.example.system.mapper.QuestionMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;


import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;


@Service
@Slf4j
public class ExamService implements IExamService {

    @Autowired
    private ExamMapper examMapper;

    @Autowired
    private QuestionMapper questionMapper;

    @Autowired
    private ExamQuestionMapper examQuestionMapper;

    @Autowired
    private RedisService redisService;

    @Autowired
    private ObjectMapper objectMapper;


    private final Integer QUESTION_ORDER = 1;

    @Override
    public TableDataInfo list(ExamQueryDTO examQueryDTO) {
        PageHelper.startPage(examQueryDTO.getPageNum(), examQueryDTO.getPageSize());
        List<ExamVo> examVos = examMapper.selectExamList(examQueryDTO);
        List<Exam> exams = examMapper.selectList(new LambdaQueryWrapper<Exam>());
        return TableDataInfo.success(examVos, exams.size());
    }

    /**
     * 没有题目列表的竞赛不允许发布
     * 校验竞赛开始时间和竞赛结束时间
     * 校验竞赛标题不能重复
     * 新增竞赛
     *
     * @param examAddDTO
     */
    @Override
    public R<Long> add(@RequestBody ExamAddDTO examAddDTO) {
        List<Exam> exist = examMapper.selectList(
                new LambdaQueryWrapper<Exam>().eq(Exam::getTitle, examAddDTO.getTitle()));
        if (!CollectionUtil.isEmpty(exist)) {
            throw new ServiceException(ResultCode.REPETITIVE_EXAM);
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime start = LocalDateTime.parse(examAddDTO.getStartTime(), formatter);
        LocalDateTime end = LocalDateTime.parse(examAddDTO.getEndTime(), formatter);
        if (end.isBefore(start)) {
            throw new ServiceException(ResultCode.SN_TIME_ERROR);
        }
        Exam add = new Exam();
        BeanUtil.copyProperties(examAddDTO, add);
        int insertExam = examMapper.insert(add);
        if (insertExam == 1) {
            return R.ok(add.getExamId(), ResultCode.SUCCESS_TO_ADD_EXAM);
        }
        return R.fail(ResultCode.FAILED_TO_ADD_EXAM);
    }

    /***
     * 通过竞赛id校验竞赛是否存在，不存在不可以添加题目
     * 校验添加的题目id是否存在  不存在不能添加改题目
     * 校验当前竞赛是否已经添加过改题目了  不允许重复添加
     * @param examQuestionAddDTO
     * @return
     */
    @Override
    public void questionAdd(@RequestBody ExamQuestionAddDTO examQuestionAddDTO) {
        Long examId = examQuestionAddDTO.getExamId();
        if (examId == null && examId < 0) {
            throw new ServiceException(ResultCode.VALID_EXAM_ID);
        }
        Exam exam = examMapper.selectById(examId);
        if (exam == null) {
            throw new ServiceException(ResultCode.NON_EXAM);
        }
        Set<Long> questions = examQuestionAddDTO.getQuestions();
        if (!CollectionUtil.isEmpty(questions)) {
            for (Long questionId : questions) {
                ExamQuestion examQuestion = new ExamQuestion();
                examQuestion.setQuestionId(examQuestionAddDTO.getExamId());
                Question question = questionMapper.selectById(questionId);
                List<ExamQuestion> examQuestions = examQuestionMapper.selectList(
                        new LambdaQueryWrapper<ExamQuestion>()
                                .eq(ExamQuestion::getExamId, examId)
                                .eq(ExamQuestion::getQuestionId, questionId));
                if (question != null && CollectionUtil.isEmpty(examQuestions)) {
                    examQuestion.setQuestionId(questionId);
                    examQuestion.setExamId(examId);
                    examQuestion.setQuestionOrder(QUESTION_ORDER);
                    examQuestionMapper.insert(examQuestion);
                }
            }
        }
    }

    @Override
    public TableDataInfo getExamQuestionList(Long questionId) {
        return null;
    }

    @Override
    public ExamVo getExamById(Long examId) {
        Exam exam = examMapper.selectById(examId);
        ExamVo examVo = new ExamVo();
        List<ExamQuestionVO> allByExamId = examQuestionMapper.getAllByExamId(examId);
        BeanUtil.copyProperties(exam, examVo);
        examVo.setExamQuestionVOS(allByExamId);
        return examVo;
    }

    @Override
    public int questionDelete(ExamQuestionDeleteDTO questionDeleteDTO) {
        int delete = examQuestionMapper.delete(new LambdaQueryWrapper<ExamQuestion>()
                .eq(ExamQuestion::getExamId, questionDeleteDTO.getExamId())
                .eq(ExamQuestion::getQuestionId, questionDeleteDTO.getQuestionId()));
        return delete;
    }

    /**
     * 先通过examid判断当前竞赛是否存在
     * 修改状态
     */

    @Override
    public int publish(Long examId) throws JsonProcessingException {
        Exam exam = examMapper.selectById(examId);
        if (exam == null) {
            throw new ServiceException(ResultCode.NON_EXAM);
        }
        String examJson = objectMapper.writeValueAsString(exam);
        redisService.setCacheObject(CacheConstants.EXAM_DETAIL + examId, examJson);
        List<String> list = new ArrayList<>();
        list.add(examJson);
        redisService.rightPushAll(CacheConstants.EXAM_UNFINISHED_LIST, list);
        exam.setStatus(1);
        int update = examMapper.updateById(exam);
        return update;
    }

    @Override
    public int unpublish(Long examId) throws JsonProcessingException {
        Exam exam = examMapper.selectById(examId);
        if (exam == null) {
            throw new ServiceException(ResultCode.NON_EXAM);
        }
        String examJson = objectMapper.writeValueAsString(exam);
        redisService.deleteObject(CacheConstants.EXAM_DETAIL + examId);
        exam.setStatus(0);
        int update = examMapper.updateById(exam);
        return update;
    }
}
